package top.bulk.web;

import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import top.bulk.common.CommonResult;
import top.bulk.enums.ServiceExceptionEnum;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * 全局异常处理器 捕获异常，包装成指定的对象
 */
@ControllerAdvice(basePackages = "top.bulk.controller")
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理 MissingServletRequestParameterException 异常
     * <p>
     * SpringMVC 参数不正确
     */
    @ResponseBody
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public CommonResult<?> missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
        log.info("[missingServletRequestParameterExceptionHandler]", ex);
        return CommonResult.err(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
    }

    /**
     * 处理 ConstraintViolationException 参数校验异常 ，包装成统一的返回数据
     */
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public CommonResult<?> constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
        log.info("[constraintViolationExceptionHandler]", ex);
        // 拼接错误， 使用 ; 分割的
        StringBuilder msg = new StringBuilder();
        for (ConstraintViolation<?> constraintViolation : ex.getConstraintViolations()) {
            if (msg.length() > 0) {
                msg.append(";");
            }
            msg.append(constraintViolation.getMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.err(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(), ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + msg.toString());
    }

    /**
     * 处理异常，其中 MethodArgumentNotValidException.class 就是继承自 BindException
     */
    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public CommonResult<?> bindExceptionHandler(HttpServletRequest req, BindException ex) {
        log.info("[bindExceptionHandler]", ex);
        // 拼接错误
        StringBuilder msg = new StringBuilder();
        for (ObjectError objectError : ex.getAllErrors()) {
            if (msg.length() > 0) {
                msg.append(";");
            }
            msg.append(objectError.getDefaultMessage());
        }
        return CommonResult.err(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(), ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + msg.toString());
    }

    /**
     * 处理其它 Exception 异常
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public CommonResult<?> exceptionHandler(HttpServletRequest req, Exception e) {
        // 记录异常日志
        log.error("[exceptionHandler]", e);
        // 返回 ERROR CommonResult
        return CommonResult.err(ServiceExceptionEnum.ERROR.getCode(), ServiceExceptionEnum.ERROR.getMessage());
    }

}
